package com.limi.java8.streams;

import com.limi.java8.lambda.practice.Employee;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

/**
 * @Description:
 * 一、Stream的三个操作步骤：
 *  1.创建Stream
 *  2.中间操作
 *  3.终止操作（终端操作）
 *
 *
 *
 * @Author Limi Pan
 * @Date 2018-10-09 21:02
 * @Version v1.0
 */
public class StreamAPI2 {

    List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 18, 8888.30),
            new Employee(2, "李四", 24, 12578.82),
            new Employee(3, "王五", 23, 4623.96),
            new Employee(4, "赵六", 25, 6578.94),
            new Employee(5, "蒋七", 31, 9578.94),
            new Employee(5, "蒋七", 31, 9578.94),
            new Employee(5, "蒋七", 31, 9578.94)
    );

    //中间操作
    /*
     * 筛选与切片:
     * filter---接收Lambda，从流中排除某些元素。
     * limit---截断流，使其元素不超过给定数量。
     * skip(n)---跳过元素，返回一个扔掉前n个元素的流。若流中元素不足n个，则返回一个空流。与limit互补。
     * distinct---筛选，通过流所生成的元素的hashCode()和equals()去除重复元素。
     */
    //内部迭代：迭代操作由Stream API完成
    @Test
    public void filterTest(){
        //中间操作
        Stream<Employee> stream = employees.stream().filter((e) -> {
            System.out.println("Stream API的中间操作");
            return e.getAge() > 23;
        });

        //终止操作：一次性执行全部内容，即“惰性求值”
        stream.forEach(System.out::println);
    }

    //外部迭代
    @Test
    public void test(){
        Iterator<Employee> it = employees.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }

    @Test
    public void limitTest(){
        employees.stream()
                .filter( e -> {
                    System.out.println("短路！");//类似&& ||
                    return e.getSalary() > 6000;
                })
                .limit(2)
                .forEach(System.out::println);
    }

    @Test
    public void skipTest(){
        employees.stream()
                .filter(e -> e.getSalary()>8000)
                .skip(2)
                .forEach(System.out::println);
    }

    @Test
    public void distinctTest(){
        employees.stream()
                .filter(e -> e.getNo() > 3)
                .distinct()//注意：需要Employee实现hashCode()和equals()
                .forEach(System.out::println);
    }

    /*
     * 映射:
     * map---接收Lambda，将元素转换成其他形式或提取信息。接收一个函数作为参数，该函数会被应用到每个元素上，
     * 并将其映射成一个新的元素。
     * flatMap---接收一个函数作为参数，将流中的每个值都换成一个流，然后把所有流连接成一个流。
     */
    @Test
    public void mapTest(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");
        list.stream()
                .map(s -> s.toUpperCase())
                //.map(String::toUpperCase)
                .forEach(System.out::println);

        employees.stream()
                //.map(e -> e.getName())
                .map(Employee::getName)//提取名字
                .forEach(System.out::println);

    }

    @Test
    public void flatMapTest(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");
        /*Stream<Stream<Character>> stream = list.stream()
                .map(StreamAPI2::filterCharacter);
        stream.forEach(sm -> {
            sm.forEach(System.out::println);
        });*/

        //应用flatMap
        Stream<Character> sm = list.stream().flatMap(StreamAPI2::filterCharacter);
        sm.forEach(System.out::println);

    }

    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    /*
     * 排序：
     * sorted()---自然排序。
     * sorted(Comparator com)---定制排序（Comparator）。
     */
    @Test
    public void sortedTest(){
        List<String> list = Arrays.asList("eee", "ccc", "aaa", "ddd", "bbb");

        //自然排序
        list.stream()
                .sorted()
                .forEach(System.out::println);

        //定制排序
        employees.stream()
                .sorted((e1, e2) -> {
                    if (e1.getAge() == e2.getAge()) {
                        return e1.getName().compareTo(e2.getName());
                    } else {
                        return Integer.compare(e1.getAge(), e2.getAge());
                    }
                }).forEach(System.out::println);
    }

}
